package com.moli.lumpSugar.user.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.moli.lumpSugar.common.cache.user.UserCache;
import com.moli.lumpSugar.common.utils.AssertUtil;
import com.moli.lumpSugar.user.dao.BlackDao;
import com.moli.lumpSugar.user.dao.ItemConfigDao;
import com.moli.lumpSugar.user.dao.UserBackpackDao;
import com.moli.lumpSugar.user.dao.UserDao;
import com.moli.lumpSugar.user.domain.dto.ItemInfoDTO;
import com.moli.lumpSugar.user.domain.dto.SummeryInfoDTO;
import com.moli.lumpSugar.user.domain.entity.Black;
import com.moli.lumpSugar.user.domain.entity.IpInfo;
import com.moli.lumpSugar.user.domain.entity.ItemConfig;
import com.moli.lumpSugar.user.domain.entity.User;
import com.moli.lumpSugar.user.domain.entity.UserBackpack;
import com.moli.lumpSugar.common.domain.enums.BlackTypeEnum;
import com.moli.lumpSugar.user.domain.enums.ItemEnum;
import com.moli.lumpSugar.user.domain.enums.ItemTypeEnum;
import com.moli.lumpSugar.user.domain.vo.req.user.BlackReq;
import com.moli.lumpSugar.user.domain.vo.req.user.ItemInfoReq;
import com.moli.lumpSugar.user.domain.vo.req.user.SummeryInfoReq;
import com.moli.lumpSugar.user.domain.vo.resp.BadgeResp;
import com.moli.lumpSugar.user.domain.vo.resp.UserInfoResp;
import com.moli.lumpSugar.user.event.BlackUserEvent;
import com.moli.lumpSugar.user.event.UserRegisterEvent;
import com.moli.lumpSugar.user.service.UserService;
import com.moli.lumpSugar.user.service.adapter.UserAdapter;
import com.moli.lumpSugar.user.service.cache.ItemCache;

import com.moli.lumpSugar.user.service.cache.UserSummaryCache;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserBackpackDao userBackpackDao;
    @Autowired
    private ItemCache itemCache;
    @Autowired
    private ItemConfigDao itemConfigDao;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    @Autowired
    private BlackDao blackDao;
    @Autowired
    private UserCache userCache;
    @Autowired
    private UserSummaryCache userSummaryCache;
//    @Autowired
//    private SensitiveWordBs sensitiveWordBs;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long register(User user) {
        userDao.saveUser(user);
        // 发送用户注册事件,使用spring的事件机制
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this,user));
        return user.getId();
    }

    @Override
    public UserInfoResp queryUserInfo(Long uid) {
        User user = userDao.getById(uid);
        Integer modifyNameChance = userBackpackDao.queryInfoByItemIdUid(ItemEnum.MODIFY_NAME_CARD.getId(), uid);
        UserInfoResp userInfoResp = UserAdapter.buildUserInfoResp(user,modifyNameChance);
        return userInfoResp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserName(Long uid,String name) {
        // 判断名字是否有要过滤的关键词
//        AssertUtil.isTrue(sensitiveWordBs.hasSensitiveWord(name), "名字中有敏感词，请重新填写吧~~");
        // 先判断名字是否重复
        User user = userDao.queryUserByName(name);
        AssertUtil.isEmpty(user,"名字被抢占了，请重新填写一个吧~~");
        UserBackpack lastModifyNameCard = userBackpackDao.getFirstValidItem(ItemEnum.MODIFY_NAME_CARD.getId(), uid);
        AssertUtil.isNotEmpty(lastModifyNameCard,"没有改名卡咯~~");
        // 扣减改名卡，进行改名
        Boolean success = userBackpackDao.modifyItem(lastModifyNameCard);
        if (success){
            userDao.updateUserName(uid,name);
            // todo 更新缓存信息
        }
    }

    @Override
    public List<BadgeResp> getBadges(Long uid) {
        // 先查询所有的徽章信息,从缓存中获取
        List<ItemConfig> itemConfigList = itemCache.getItemConfigList(ItemTypeEnum.BADGE.getType());
        // 查询用户背包信息，判断是否拥有
        List<UserBackpack> backpackList = userBackpackDao.getByItems(uid, itemConfigList.stream().map(ItemConfig::getId).collect(Collectors.toList()));
        // 查询用户佩戴的哪一个
        User user = userDao.getById(uid);
        return UserAdapter.buildBadgesInfoResp(itemConfigList,backpackList,user);
    }

    @Override
    public void waringBadge(Long uid, Long itemId) {
        // 先查询是用户背包中否有此徽章物品
        UserBackpack firstValidItem = userBackpackDao.getFirstValidItem(itemId, uid);
        AssertUtil.isNotEmpty(firstValidItem,"没有此徽章，请先去获得此徽章吧~~");
        // 校验此物品是徽章
        ItemConfig itemInfo = itemConfigDao.getById(itemId);
        AssertUtil.isTrue(ItemTypeEnum.BADGE.getType().equals(itemInfo.getType()),"此物品不是徽章，只能佩戴徽章哦~~");
        // 修改用户信息，佩戴徽章
        userDao.waringBadge(uid,itemId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void black(BlackReq req) {
        // 要拉黑用户的uid
        Long uid = req.getUid();
        Black black = new Black();
        // 拉黑用户id
        black.setTarget(String.valueOf(uid));
        black.setType(BlackTypeEnum.UID.getType());
        blackDao.save(black);
        // 拉黑用户ip
        User blackUser = userDao.getById(uid);
        blackIp(Optional.ofNullable(blackUser.getIpInfo()).map(IpInfo::getCreateIp).orElse(null));
        blackIp(Optional.ofNullable(blackUser.getIpInfo()).map(IpInfo::getUpdateIp).orElse(null));
        // 推送拉黑事件
        applicationEventPublisher.publishEvent(new BlackUserEvent(this,blackUser));

    }

    @Override
    public UserInfoResp getUserInfo(Long uid) {
        com.moli.lumpSugar.api.domain.entity.user.User oldUser = userCache.getUserInfo(uid);
        User userInfo = new User();
        BeanUtil.copyProperties(oldUser,userInfo);
        Integer countByValidItemId = userBackpackDao.getCountByValidItemId(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        return UserAdapter.buildUserInfoResp(userInfo, countByValidItemId);
    }

    @Override
    public List<SummeryInfoDTO> getSummeryUserInfo(SummeryInfoReq req) {
        //需要前端同步的uid
        List<Long> uidList = getNeedSyncUidList(req.getReqList());
        //加载用户信息
        Map<Long, SummeryInfoDTO> batch = userSummaryCache.getBatch(uidList);
        return req.getReqList()
                .stream()
                .map(a -> batch.containsKey(a.getUid()) ? batch.get(a.getUid()) : SummeryInfoDTO.skip(a.getUid()))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    @Override
    public List<ItemInfoDTO> getItemInfo(ItemInfoReq req) {
        return req.getReqList().stream().map(a -> {
            ItemConfig itemConfig = itemCache.getById(a.getItemId());
            if (Objects.nonNull(a.getLastModifyTime()) && a.getLastModifyTime() >= itemConfig.getUpdateTime().getTime()) {
                return ItemInfoDTO.skip(a.getItemId());
            }
            ItemInfoDTO dto = new ItemInfoDTO();
            dto.setItemId(itemConfig.getId());
            dto.setImg(itemConfig.getImg());
            dto.setDescribe(itemConfig.getDescribe());
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public User getUser(Long uid) {
        return userDao.getById(uid);
    }

    @Override
    public User getUserByOpenId(String openId) {
        return userDao.queryUserByOpenId(openId);
    }

    @Override
    public List<User> getUserListByIds(List<Long> ids) {
        return userDao.listByIds(ids);
    }

    @Override
    public Boolean updateUserById(User user) {
        return userDao.updateById(user);
    }

    private void blackIp(String ip) {
        if (StringUtils.isBlank(ip)) {
            return;
        }
        try {
            Black insert = new Black();
            insert.setType(BlackTypeEnum.IP.getType());
            insert.setTarget(ip);
            blackDao.save(insert);
        } catch (Exception e) {

        }

    }

    private List<Long> getNeedSyncUidList(List<SummeryInfoReq.infoReq> reqList) {
        List<Long> needSyncUidList = new ArrayList<>();
        List<Long> userModifyTime = userCache.getUserModifyTime(reqList.stream().map(SummeryInfoReq.infoReq::getUid).collect(Collectors.toList()));
        for (int i = 0; i < reqList.size(); i++) {
            SummeryInfoReq.infoReq infoReq = reqList.get(i);
            Long modifyTime = userModifyTime.get(i);
            if (Objects.isNull(infoReq.getLastModifyTime()) || (Objects.nonNull(modifyTime) && modifyTime > infoReq.getLastModifyTime())) {
                needSyncUidList.add(infoReq.getUid());
            }
        }
        return needSyncUidList;
    }


}
